import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';

class Http {
	static final Http _instance = Http._();
	static Http get instance => Http();

	factory Http() => _instance;

	static late Dio _dio;
	Dio get dio => _dio;

	Http._() {
		// 构造 Dio options
		final BaseOptions options = BaseOptions(
			receiveTimeout: const Duration(seconds: 10),
			connectTimeout: const Duration(seconds: 10),
			sendTimeout: const Duration(seconds: 8),
			responseType: ResponseType.json,
			validateStatus: (_) => true,
			baseUrl: "http://localhost:8000",
		);

		_dio = Dio(options);

		if (kDebugMode) {
			// 日志
			_dio.interceptors.add(PrettyDioLogger(
				requestHeader: true,
				requestBody: true,
				responseBody: true,
				responseHeader: true,
				error: true,
				compact: true,
				maxWidth: 90
			));
		}

		_dio.interceptors.add(HttpInterceptor());
	}

	BaseError getError(Object obj) {  // 这里封装了一个 BaseError 类，会根据后端返回的code返回不同的错误类
		switch (obj.runtimeType) {
			case DioException :
			if ((obj as DioException ).type == DioExceptionType .badResponse) {
				final response = (obj).response;
				if (response?.statusCode == 401) {
					return NeedLogin();
				} else if (response?.statusCode == 403) {
					return NeedAuth();
				} else if (response?.statusCode == 408) {
					return UserNotExist();
				} else if (response?.statusCode == 409) {
					return PwdNotMatch();
				} else if (response?.statusCode == 405) {
					return UserNameEmpty();
				} else if (response?.statusCode == 406) {
					return PwdEmpty();
				} else {
					return OtherError(
						statusCode: response?.statusCode as int,
						statusMessage: response?.statusMessage as String,
					);
				}
			}
		}

		return OtherError(statusCode: -1, statusMessage: '未知错误');
	}
}

class HttpInterceptor extends Interceptor {
	late DateTime startTime;
	late DateTime endTime;

	@override
	void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
		startTime = DateTime.now();

		if (kDebugMode) {
			print("-------- Http Interceptor start --------");
		}
		return handler.next(options);
	}

	@override
	void onResponse(Response response, ResponseInterceptorHandler handler) {
		endTime = DateTime.now();
		int duration = endTime.difference(startTime).inMilliseconds;

		if (kDebugMode) {
			print("-------- Http Interceptor end: $duration 毫秒 --------");
		}
		if(response.statusCode!>299||response.statusCode!<200){
			throw DioException(requestOptions:RequestOptions(),type:DioExceptionType.badResponse,response:response,message: response.statusMessage);
		}

		return handler.next(response);
	}

	@override
	void onError(DioException err, ErrorInterceptorHandler handler) {
		super.onError(err, handler);
		if(err.type==DioExceptionType.connectionError||err.type==DioExceptionType.connectionTimeout){
			if (kDebugMode) {
		  	  	print('网络错误: ${err.message}');
		  	}
		}else{
			if (kDebugMode) {
		  	  	print('请求错误: ${err.response?.statusCode}-${err.message}');
		  	}
		}
	}
}

abstract class BaseError {
  final int code;
  final String message;

  BaseError({required this.code, required this.message});
}

class NeedLogin implements BaseError {
  @override
  int get code => 401;

  @override
  String get message => "请先登录";
}

class NeedAuth implements BaseError {
  @override
  int get code => 403;

  @override
  String get message => "非法访问，请使用正确的token";
}

class UserNotExist implements BaseError {
  @override
  int get code => 408;

  @override
  String get message => "用户不存在";
}

class UserNameEmpty implements BaseError {
  @override
  int get code => 405;

  @override
  String get message => "用户名不能为空";
}

class PwdNotMatch implements BaseError {
  @override
  int get code => 409;

  @override
  String get message => "用户密码不正确";
}

class PwdEmpty implements BaseError {
  @override
  int get code => 406;

  @override
  String get message => "用户密码不能为空";
}

class OtherError implements BaseError {

  final int statusCode;
  final String statusMessage;

  OtherError({required this.statusCode, required this.statusMessage});

  @override
  int get code => statusCode;

  @override
  String get message => statusMessage;

}
